import type {Component} from 'vue';
import {defineComponent, defineAsyncComponent, getCurrentInstance, h, ref} from 'vue';
import type {Recordable} from '#/typings';

import {$t} from '#/locales';

import {globalShareState} from '#/utils';

import {setupForm} from './form-ui'
import {setupVxeTable} from './vxe-table-ui'

import {ApiComponent, IconPicker,} from '#/components/common-ui';
import {
    BasicCheckbox,
    BasicInputPassword,
    BasicPinInput,
    BasicSelect,
    Input as BasicInput,
} from '#/components/shadcn-ui'

import {
    notification,
} from 'ant-design-vue';

const AutoComplete = defineAsyncComponent(
    () => import('ant-design-vue/es/auto-complete'),
);
const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
const Checkbox = defineAsyncComponent(
    () => import('ant-design-vue/es/checkbox'),
);
const CheckboxGroup = defineAsyncComponent(() =>
    import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
);
const DatePicker = defineAsyncComponent(
    () => import('ant-design-vue/es/date-picker'),
);
const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
const InputNumber = defineAsyncComponent(
    () => import('ant-design-vue/es/input-number'),
);
const InputPassword = defineAsyncComponent(() =>
    import('ant-design-vue/es/input').then((res) => res.InputPassword),
);
const Mentions = defineAsyncComponent(
    () => import('ant-design-vue/es/mentions'),
);
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
const RadioGroup = defineAsyncComponent(() =>
    import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
    import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
);
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
const Textarea = defineAsyncComponent(() =>
    import('ant-design-vue/es/input').then((res) => res.Textarea),
);
const TimePicker = defineAsyncComponent(
    () => import('ant-design-vue/es/time-picker'),
);
const TreeSelect = defineAsyncComponent(
    () => import('ant-design-vue/es/tree-select'),
);
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));

/**
 * 通用组件共同的使用的基础组件,可用于 form、modal、drawer 等组件使用,
 * 自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明
 */
export type ComponentType =
    | 'DefaultButton'
    | 'PrimaryButton'
    | 'BasicCheckbox'
    | 'BasicInput'
    | 'BasicInputPassword'
    | 'BasicPinInput'
    | 'BasicSelect'
    | 'ApiSelect'
    | 'ApiTreeSelect'
    | 'AutoComplete'
    | 'Checkbox'
    | 'CheckboxGroup'
    | 'DatePicker'
    | 'Divider'
    | 'IconPicker'
    | 'Input'
    | 'InputNumber'
    | 'InputPassword'
    | 'Mentions'
    | 'Radio'
    | 'RadioGroup'
    | 'RangePicker'
    | 'Rate'
    | 'Select'
    | 'Space'
    | 'Switch'
    | 'Textarea'
    | 'TimePicker'
    | 'TreeSelect'
    | 'Upload'
    | (Record<never, never> & string);

export async function initComponent() {
    const components: Partial<Record<ComponentType, Component>> = {
        // 如果你的组件体积比较大，可以使用异步加载
        // Button: () =>
        // import('xxx').then((res) => res.Button),
        // 自定义默认按钮
        DefaultButton: (props, {attrs, slots}) => {
            return h(Button, {...props, attrs, type: 'default'}, slots);
        },
        // 自定义主要按钮
        PrimaryButton: (props, {attrs, slots}) => {
            return h(Button, {...props, attrs, type: 'primary'}, slots);
        },
        BasicCheckbox,
        BasicInput,
        BasicInputPassword,
        BasicPinInput,
        BasicSelect,
        ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', {
            component: Select,
            loadingSlot: 'suffixIcon',
            modelPropName: 'value',
            visibleEvent: 'onVisibleChange',
        }),
        ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', {
            component: TreeSelect,
            fieldNames: { label: 'label', value: 'value', children: 'children' },
            loadingSlot: 'suffixIcon',
            modelPropName: 'value',
            optionsPropName: 'treeData',
            visibleEvent: 'onVisibleChange',
        }),
        AutoComplete,
        Checkbox,
        CheckboxGroup,
        DatePicker,
        Divider,
        IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
            iconSlot: 'addonAfter',
            inputComponent: Input,
            modelValueProp: 'value',
        }),
        Input: withDefaultPlaceholder(Input, 'input'),
        InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
        InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
        Mentions: withDefaultPlaceholder(Mentions, 'input'),
        Radio,
        RadioGroup,
        RangePicker,
        Rate,
        Select: withDefaultPlaceholder(Select, 'select'),
        Space,
        Switch,
        Textarea: withDefaultPlaceholder(Textarea, 'input'),
        TimePicker,
        TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
        Upload,
    };

    // 将组件注册到全局共享状态中
    globalShareState.setComponents(components);

    // 定义全局共享状态中的消息提示
    globalShareState.defineMessage({
        // 复制成功消息提示
        copyPreferencesSuccess: (title, content) => {
            notification.success({
                description: content,
                message: title,
                placement: 'bottomRight',
            });
        },
    });

    // 初始化表单和表格
    await setupForm();
    await setupVxeTable();
}

const withDefaultPlaceholder = <T extends Component>(
    component: T,
    type: 'input' | 'select',
    componentProps: Recordable<any> = {},
) => {
    return defineComponent({
        inheritAttrs: false,
        name: component.name,
        setup: (props: any, {attrs, expose, slots}) => {
            const placeholder =
                props?.placeholder ||
                attrs?.placeholder ||
                $t(`ui.placeholder.${type}`);
            // 透传组件暴露的方法
            const innerRef = ref();
            const publicApi: Recordable<any> = {};
            expose(publicApi);
            const instance = getCurrentInstance();
            instance?.proxy?.$nextTick(() => {
                for (const key in innerRef.value) {
                    if (typeof innerRef.value[key] === 'function') {
                        publicApi[key] = innerRef.value[key];
                    }
                }
            });
            return () =>
                h(
                    component,
                    { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
                    slots,
                );
        },
    });
};